package com.vois.jack.btmgr.classicbase;

import com.vois.jack.btmgr.common.DeviceRecorderControlInterface;
import com.vois.jack.btmgr.util.DataRingBuffer;
import com.vois.jack.btmgr.util.Logger;
import com.voistech.sbccoder.SBCCodec;


public class BtSBCCodecRecorder implements BtRecorderInterface {
    private Logger logger = Logger.getLogger(BtSBCCodecRecorder.class);
    private boolean isStarted;
    private DataRingBuffer dataRingBuffer;
    private SBCCodec sbcCodec;
    private final int MAX_AUDIO_BUFFER_SIZE = 48000 * 2;
    private int frameSize = 0;
    private short[] pcmFrameBuf;
    private int[] outputFrameSize;

    private int sbcSampleRate;
    private int sbcBlock;
    private int sbcChannelMode;
    private int sbcAm;
    private int sbcSubBand;
    private int sbcBitpool;

    @Override
    public void create(int audioSource, int sampleRate) {
        logger.d("create SBCCodec");
        isStarted = false;
        dataRingBuffer = new DataRingBuffer("BtSbcRecorder", MAX_AUDIO_BUFFER_SIZE, false);

        sbcSampleRate = SBCCodec.SBC_FREQ_16000;
        sbcBlock = SBCCodec.SBC_BLK_16;
        sbcChannelMode = SBCCodec.SBC_MODE_MONO;
        sbcAm = SBCCodec.SBC_AM_LOUDNESS;
        sbcSubBand = SBCCodec.SBC_SB_8;
        sbcBitpool = 14;
    }


    @Override
    public void release() {
        logger.d("release SBCCodec");
        if (dataRingBuffer != null) {
            dataRingBuffer.destroyBuffer();
            dataRingBuffer = null;
        }
    }

    @Override
    public int getAudioSource() {
        return 0;
    }

    @Override
    public int getSampleRate() {
        int sampleRate = 16000;
        switch (sbcSampleRate) {
            case SBCCodec.SBC_FREQ_16000: {
                sampleRate = 16000;
            }
            break;

            case SBCCodec.SBC_FREQ_32000: {
                sampleRate = 32000;
            }
            break;

            case SBCCodec.SBC_FREQ_44100: {
                sampleRate = 44100;
            }
            break;

            case SBCCodec.SBC_FREQ_48000: {
                sampleRate = 48000;
            }
            break;
        }

        return sampleRate;
    }

    public boolean setSbcParameters(int sampleRate, int blocks, int channelMode,
                                    int am, int subband, int bitpool) {
        if (sampleRate >= SBCCodec.SBC_FREQ_16000 && sampleRate <= SBCCodec.SBC_FREQ_48000) {
            sbcSampleRate = sampleRate;
        }else {
            return false;
        }

        if (blocks >= SBCCodec.SBC_BLK_4 && blocks <= SBCCodec.SBC_BLK_16) {
            sbcBlock = blocks;
        }else {
            return false;
        }

        if (channelMode >= SBCCodec.SBC_MODE_MONO && channelMode <= SBCCodec.SBC_MODE_JOINT_STEREO) {
            sbcChannelMode = channelMode;
        }else {
            return false;
        }

        if (am >= SBCCodec.SBC_AM_LOUDNESS && am <= SBCCodec.SBC_AM_SNR) {
            sbcAm = am;
        }else {
            return false;
        }

        if (subband >= SBCCodec.SBC_SB_4 && subband <= SBCCodec.SBC_SB_8) {
            sbcSubBand = subband;
        }else {
            return false;
        }

        if (bitpool >=0 && bitpool <= 32) {
            sbcBitpool = bitpool;
        }else {
            return false;
        }

        return true;
    }

    @Override
    public void startRecord() {
        logger.d("before startRecord isStarted:" + isStarted);
        if (!isStarted) {
            sbcCodec = new SBCCodec();
            isStarted = sbcCodec.init(sbcSampleRate, sbcBlock, sbcChannelMode,
                    sbcAm, sbcSubBand, sbcBitpool);

            frameSize = sbcCodec.getCodeSize() / 2;
            pcmFrameBuf = new short[frameSize * 2];
            outputFrameSize = new int[1];


            if (dataRingBuffer != null) {
                try {
                    dataRingBuffer.clearBuffer();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                    isStarted = false;
                }
            }
        }
        logger.d("after startRecord isStarted:" + isStarted);
    }

    @Override
    public void stopRecord() {
        logger.d("stopRecord");
        if (isStarted) {
            isStarted = false;
            sbcCodec.deInit();
            sbcCodec = null;
            pcmFrameBuf = null;
        }
    }

    @Override
    public int putRecordData(byte[] rawData, int offset, int rawDataSize) {
        return 0;
    }

    @Override
    public int readRecordData(short[] audioData, int offsetInShort, int sizeInShort) {
        try {
            int leftSize = 0;
            int getSize = -1;

            while (dataRingBuffer != null && leftSize < sizeInShort) {
                getSize = dataRingBuffer.getData(audioData, leftSize, sizeInShort - leftSize);
                leftSize += getSize;
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
            logger.d("get interruptException");
        }catch (Exception e) {
            logger.d("some error happened!!!!");
            try {
                dataRingBuffer.clearBuffer();
            }catch (InterruptedException e2) {
                logger.d("clear buffer was interrupted");
                e2.printStackTrace();
            }
            e.printStackTrace();
        }

        return sizeInShort;
    }

    @Override
    public int putEncodedRecordData(byte[] rawData, int offsetInByte, int rawDataSize) {

        int ret = 0;

        if (!isStarted) {
            return 0;
        }

        byte[] sbcData = new byte[rawDataSize];
        System.arraycopy(rawData, offsetInByte, sbcData, 0, rawDataSize);

        try {
            while (rawDataSize > 0) {
                ret = sbcCodec.decode(sbcData, rawDataSize, pcmFrameBuf, frameSize, outputFrameSize);
                //logger.d("xxx: rawDataSize:" + rawDataSize + " frameSize:" + frameSize + "\n\tret:" + ret + " outputFrameSize:" + outputFrameSize[0]);

                if (ret > 0) {
                    rawDataSize -= ret;
                    if (rawDataSize > 0) {
                        for (int i = 0; i < rawDataSize; i++) {
                            sbcData[i] = sbcData[ret + i];
                        }
                    }
                    dataRingBuffer.putData(pcmFrameBuf, 0, outputFrameSize[0]);
                }
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }catch (Exception e) {
            try {
                if (dataRingBuffer != null) {
                    dataRingBuffer.clearBuffer();
                }
            }catch (InterruptedException e2) {
                e2.printStackTrace();
            }
        }

        return rawDataSize;
    }

    @Override
    public int getEncodedRecordData(byte[] rawData) {
        return 0;
    }

    @Override
    public int getAudioSessionId() {
        return 0;
    }

    @Override
    public int getRecordDataType() {
        return RAW_RECORD_DATA;
    }
}
